#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
 
#include "data_type.h"
#include "alloc.h"
#include "memfunc.h"
#include "basefunc.h"
#include "struct_deal.h"
#include "crypto_func.h"
#include "memdb.h"
#include "message.h"
#include "return_value.h"
#include "ex_module.h"
#include "sys_func.h"
#include "server_manage.h"
#include "tcm_constants.h"
#include "tcm_structures.h"
#include "tcm_key_manage.h"
#include "tcm_key_desc.h"
#include "tcm_pik_desc.h"
#include "system_entity.h"
#include "integrity_measure.h"

// add para lib_include
BYTE Buf[DIGEST_SIZE*16];
int iswritepcr=0;
RECORD(INTEGRITY_COLLECT,UNITSET_MEASURE) * whitelist_find_byname(char * name);

int server_manage_init(void * sub_proc, void * para)
{
	int ret;
	// add yorself's module init func here
	return 0;
}
int server_manage_start(void * sub_proc, void * para)
{
	int ret;
	void * recv_msg;
	int type;
	int subtype;
	// add yorself's module exec func here
	while(1)
	{
		usleep(time_val.tv_usec);
		ret=ex_module_recvmsg(sub_proc,&recv_msg);
		if(ret<0)
			continue;
		if(recv_msg==NULL)
			continue;
		type=message_get_type(recv_msg);
		subtype=message_get_subtype(recv_msg);
		if(!memdb_find_recordtype(type,subtype))
		{
			printf("message format (%d %d) is not registered!\n",
			message_get_type(recv_msg),message_get_subtype(recv_msg));
			continue;
		}
		if((type==TYPE(INTEGRITY_COLLECT))&&(subtype==SUBTYPE(INTEGRITY_COLLECT,UNITSET_MEASURE)))
		{
			ret=proc_server_pcrwrite(sub_proc,recv_msg);
		}
		else if((type==TYPE(GENERAL_RETURN))&&(subtype==SUBTYPE(GENERAL_RETURN,STRING)))
		{
			ret=proc_report_choice(sub_proc,recv_msg);
		}
	}
	return 0;
}

int proc_server_pcrwrite(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(INTEGRITY_COLLECT,UNITSET_MEASURE) * measure_value;
	RECORD(GENERAL_RETURN,UUID) * extend_info;
	void * send_msg;

	int i=0;
	send_msg=message_create(TYPE_PAIR(GENERAL_RETURN,UUID),recv_msg);
	if(send_msg==NULL)
		return -EINVAL;

	ret=message_get_record(recv_msg,&measure_value,i++);
	if(ret<0)
		return ret;
	if(iswritepcr==0)
	{
		extend_info=Talloc0(sizeof(*extend_info));
		extend_info->name=dup_str("pcrreset",0);
		message_add_record(send_msg,extend_info);
	}
	while(measure_value != NULL)
	{
		extend_info=Talloc0(sizeof(*extend_info));
		extend_info->name=dup_str("extend",0);
		Memcpy(extend_info->return_value,measure_value->uuid,DIGEST_SIZE);
		message_add_record(send_msg,extend_info);
		ret=message_get_record(recv_msg,&measure_value,i++);
	}
	ret=ex_module_sendmsg(sub_proc,send_msg);
	return ret;
}

int proc_report_choice(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(GENERAL_RETURN,STRING) * report_request;
	RECORD(INTEGRITY_COLLECT,UNITSET_MEASURE) * whitelist;
	RECORD(SYSTEM_ENTITY,UNIT_SET) * unitset;
	RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote;
	void * new_msg;

	ret=message_get_record(recv_msg,&report_request,0);
	if(ret<0)
		return -EINVAL;
	if(report_request==NULL)
		return -EINVAL;
	printf("enter report choice\n");
	
	if(Strcmp(report_request->name,"whitelist")==0)
	{
		printf("enter whitelist\n");
		whitelist=whitelist_find_byname(report_request->return_value);
		if(whitelist==NULL)
			return -EINVAL;
		printf("find whitelist\n");
		new_msg=message_create(TYPE_PAIR(INTEGRITY_COLLECT,UNITSET_MEASURE),recv_msg);
		if(new_msg==NULL)
			return -EINVAL;
		message_add_record(new_msg,whitelist);
		ret=ex_module_sendmsg(sub_proc,new_msg);
	}	
	else if(Strcmp(report_request->name,"pcrquote")==0)
	{
		new_msg=message_create(TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),recv_msg);
		if(new_msg==NULL)
			return -EINVAL;
		pcrquote=Talloc0(sizeof(*pcrquote));
		if(pcrquote==NULL)
			return -ENOMEM;	
		TCM_ExInitPcrComposite(&pcrquote->pcrComp);
		TCM_ExAddPcrComposite(&pcrquote->pcrComp,14,NULL);

		RAND_bytes(pcrquote->nonce,DIGEST_SIZE);
		
		message_add_record(new_msg,pcrquote);

		ret=ex_module_sendmsg(sub_proc,new_msg);
	}
	return ret;
}

RECORD(INTEGRITY_COLLECT,UNITSET_MEASURE) * whitelist_find_byname(char * name)
{
	int ret;
	RECORD(SYSTEM_ENTITY,UNIT_SET) * system_entity;
	RECORD(INTEGRITY_COLLECT,UNITSET_MEASURE) * measure_result;
	DB_RECORD *db_record;
	BYTE Compname[DIGEST_SIZE];
	
	Memset(Compname,0,DIGEST_SIZE);
	Strncpy(Compname,name,DIGEST_SIZE);
	
	db_record=memdb_find_first(TYPE_PAIR(SYSTEM_ENTITY,UNIT_SET),"name",Compname);
	if(db_record==NULL)
	{
		printf("can't find system_entity %s!\n",name);
		return NULL;
	}
	system_entity=db_record->record;
	if(system_entity==NULL)
		return NULL;
	db_record=memdb_find_byname(Compname,TYPE_PAIR(INTEGRITY_COLLECT,UNITSET_MEASURE));
	if(db_record==NULL)
		return NULL;
	return db_record->record;
}
